#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "touch_button.h"
#include "flexible_button.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/touch_pad.h"
#include "esp_log.h"
#include "ledc.h"

#define ENUM_TO_STR(e) (#e)


#define TOUCH_BUTTON_IO (0u)
#define TOUCH_PAD_NO_CHANGE   (-1)
#define TOUCH_THRESH_NO_USE   (0)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)

#define IS_PRINT_LOG    (0)

typedef enum{
    CTRL_MODE,
    CHANGE_COLOR_MODE,
    CHANGE_BRIGHT_MODE,
    CHAGNE_SATURATION_MODE,
    NUM_MODE
}touch_mode_t;

static touch_mode_t touch_mode;

typedef enum
{
    TOUCH_BUTTON_0 = 0,
    USER_BUTTON_MAX
} user_button_t;

static const char *TAG = "Touch";

#if IS_PRINT_LOG
static char *enum_event_string[] = {
    ENUM_TO_STR(FLEX_BTN_PRESS_DOWN),
    ENUM_TO_STR(FLEX_BTN_PRESS_CLICK),
    ENUM_TO_STR(FLEX_BTN_PRESS_DOUBLE_CLICK),
    ENUM_TO_STR(FLEX_BTN_PRESS_REPEAT_CLICK),
    ENUM_TO_STR(FLEX_BTN_PRESS_SHORT_START),
    ENUM_TO_STR(FLEX_BTN_PRESS_SHORT_UP),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_START),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_UP),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_HOLD),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_HOLD_UP),
    ENUM_TO_STR(FLEX_BTN_PRESS_MAX),
    ENUM_TO_STR(FLEX_BTN_PRESS_NONE),
};

static char *enum_btn_id_string[] = {
    ENUM_TO_STR(TOUCH_BUTTON_0),
    ENUM_TO_STR(USER_BUTTON_MAX),
};
#endif

static uint16_t touch_default_vaule = 0;
static uint16_t touch_default_15_percent_value = 0;



static flex_button_t user_button[USER_BUTTON_MAX];

static uint8_t common_btn_read(void *arg)
{
    uint8_t value = 0;

    flex_button_t *btn = (flex_button_t *)arg;

    switch (btn->id)
    {
    case TOUCH_BUTTON_0:
        uint16_t touch_filter_value;
        touch_pad_read_filtered(TOUCH_BUTTON_IO, &touch_filter_value);
        if(touch_filter_value >= touch_default_vaule){
            if((touch_filter_value - touch_default_vaule) >= (touch_default_15_percent_value)){
                #if IS_PRINT_LOG
                ESP_LOGI(TAG,"touch value %d,default value %d",touch_filter_value,touch_default_vaule);
                #endif
                value = 0;
            }else{
                value = 1;
            }
        }else{
            if((touch_default_vaule - touch_filter_value) >= (touch_default_15_percent_value)){
                value = 0;
                #if IS_PRINT_LOG
                ESP_LOGI(TAG,"touch value %d,default value %d",touch_filter_value,touch_default_vaule);
                #endif
            }else{
                value = 1;
            }            
        }
        break;
    default:
    }

    return value;
}

static void common_btn_evt_cb(void *arg)
{
    #if IS_PRINT_LOG
    flex_button_t *btn = (flex_button_t *)arg;
    ESP_LOGI(TAG,"id: [%d - %s]  event: [%d - %30s]  repeat: %d\n", 
        btn->id, enum_btn_id_string[btn->id],
        btn->event, enum_event_string[btn->event],
        btn->click_cnt);
    #endif
    if(flex_button_event_read(&user_button[TOUCH_BUTTON_0]) == FLEX_BTN_PRESS_LONG_START){
        switch (touch_mode)
        {
        case CTRL_MODE:
            break;
        case CHANGE_COLOR_MODE:
            touch_mode = CTRL_MODE;
            break;    
        case CHAGNE_SATURATION_MODE:
            touch_mode = CTRL_MODE;
            break; 
        case CHANGE_BRIGHT_MODE:
            touch_mode = CTRL_MODE;
            break;         
        default:
            break;
        }
        ESP_LOGI(TAG,"touch button 0 press long start\n");
    }

    if(flex_button_event_read(&user_button[TOUCH_BUTTON_0]) == FLEX_BTN_PRESS_DOUBLE_CLICK){
        switch (touch_mode)
        {
        case CTRL_MODE:
            touch_mode = CHANGE_COLOR_MODE;
            break;
        case CHANGE_COLOR_MODE:
            touch_mode = CHAGNE_SATURATION_MODE;
            break;    
        case CHAGNE_SATURATION_MODE:
            touch_mode = CHANGE_BRIGHT_MODE;
            break; 
        case CHANGE_BRIGHT_MODE:
            touch_mode = CTRL_MODE;
            break;      
        default:
            break;
        }
        ESP_LOGI(TAG,"touch button 0 double click\n");
    }

    if(flex_button_event_read(&user_button[TOUCH_BUTTON_0]) == FLEX_BTN_PRESS_CLICK)
    {
        switch (touch_mode)
        {
        case CTRL_MODE:
            set_led_state_reverse();
            break;
        case CHANGE_COLOR_MODE:
            set_led_change_color();
            break;  
        case CHANGE_BRIGHT_MODE:
            set_led_brightness_down();
            break;   
        case CHAGNE_SATURATION_MODE:
            set_led_saturation_down();
            break;             
        default:
            break;
        }
        ESP_LOGI(TAG,"touch button 0 click\n");
    }
    ESP_LOGI(TAG,"touch button current mode is %d\n",touch_mode);

}

static void button_scan(void *arg)
{
    while(1)
    {
        flex_button_scan();
        vTaskDelay(20 / portTICK_PERIOD_MS);
    }
}

static void user_button_init(void)
{
    int i;
    
    memset(&user_button[0], 0x0, sizeof(user_button));

    // Initialize touch pad peripheral.
    // The default fsm mode is software trigger mode.
    ESP_ERROR_CHECK(touch_pad_init());
    // Set reference voltage for charging/discharging
    // In this case, the high reference valtage will be 2.7V - 1V = 1.7V
    // The low reference voltage will be 0.5
    // The larger the range, the larger the pulse count value.
    touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
    touch_pad_config(TOUCH_BUTTON_IO, TOUCH_THRESH_NO_USE);
    touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
    touch_pad_read_filtered(TOUCH_BUTTON_IO, &touch_default_vaule);
    touch_default_15_percent_value = 0.15*touch_default_vaule;

    for (i = 0; i < USER_BUTTON_MAX; i ++)
    {
        user_button[i].id = i;
        user_button[i].usr_button_read = common_btn_read;
        user_button[i].cb = common_btn_evt_cb;
        user_button[i].pressed_logic_level = 0;
        user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500);
        user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000);
        user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500);
        flex_button_register(&user_button[i]);
    }
}

int touch_button_init(void)
{
    user_button_init();

    xTaskCreate(&button_scan, "button_scan_task", 4096, NULL, 5, NULL);

    return 0;
}